package com.real.fact.web.customer.application;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.validation.Errors;

import com.globant.katari.core.application.ValidatableCommand;
import com.real.fact.web.customer.domain.Payment;
import com.real.fact.web.customer.domain.Customer;
import com.real.fact.web.customer.domain.CustomerRepository;
import com.real.fact.web.sale.domain.Check;
import com.real.fact.web.sale.domain.Sale;
import com.real.fact.web.sale.domain.SalePayment;
import com.real.fact.web.sale.domain.SaleRepository;
import com.real.fact.web.sale.domain.Ticket;

public class AddPaymentCommand implements ValidatableCommand<Void> {

  private final CustomerRepository customerRepository;

  private final SaleRepository saleRepository;

  private final Map<String, String> selection;

  private final Map<String, String> ticketTypes;
  
  private String ticketTypeSelected = Ticket.NONE.toString();

  private float totalSale;
  
  private long customerId;

  private float amountDebitCard;

  private float amountCreditCard;

  private float amountCash;

  private String checkNumber;

  private String checkBank;

  private Date paymentDate;

  private float checkAmount;

  /**
   * @param theCustomerRepository
   * @param theSaleRepository
   */
  public AddPaymentCommand(final CustomerRepository theCustomerRepository,
      final SaleRepository theSaleRepository) {
    customerRepository = theCustomerRepository;
    saleRepository = theSaleRepository;
    selection = new HashMap<String, String>();
    ticketTypes = new HashMap<String, String>();
    ticketTypes.put(Ticket.A.toString(), "Factura A");
    ticketTypes.put(Ticket.B.toString(), "Factura B");
    ticketTypes.put(Ticket.NONE.toString(), "N/A");
    ticketTypes.put(Ticket.R.toString(), "Remito");
  }

  public Void execute() {
    List<Sale> toPay = new ArrayList<Sale>();
    for (Entry<String, String> entry : selection.entrySet()) {
      if ("on".equals(entry.getValue())) {
        toPay.add(saleRepository.findById(Long.parseLong(entry.getKey())));
      }
    }
    Customer customer = customerRepository.findById(customerId);
    float moneyLeft = totalSale;
    Check check = null;
    if (checkAmount > 0) {
      check = new Check(checkNumber, checkBank, checkAmount, paymentDate);
    }
    Payment theAdjustment = new Payment(amountCash, amountDebitCard, amountCreditCard, customer,
        "", check, Ticket.valueOf(ticketTypeSelected));
    customerRepository.save(theAdjustment);
    customer.addAdjustment(totalSale);
    customerRepository.save(customer);
    for (Sale sale : toPay) {
      if (moneyLeft > 0) {
        float debt = calculateDebt(sale);
        float saleAmount = Math.min(moneyLeft, debt);
        SalePayment payment = new SalePayment(theAdjustment, sale, saleAmount);
        saleRepository.save(payment);
        moneyLeft -= Math.min(moneyLeft, debt);
      } else {
        break; // Not more money to pay.
      }
    }
    return null;
  }

  private float calculateDebt(Sale sale) {
    List<SalePayment> payments = sale.getPayments();
    float payed = 0;
    float total = sale.getTotal();
    for (SalePayment payment : payments) {
      payed += payment.getAmount();
    }
    return total - payed;
  }

  public float getTotalSale() {
    return totalSale;
  }

  public void setTotalSale(float totalAmount) {
    this.totalSale = totalAmount;
  }

  public Map<String, String> getSelection() {
    return selection;
  }

  public long getCustomerId() {
    return customerId;
  }

  public void setCustomerId(long customerId) {
    this.customerId = customerId;
  }

  public float getAmountDebitCard() {
    return amountDebitCard;
  }

  public void setAmountDebitCard(float amountDebitCard) {
    this.amountDebitCard = amountDebitCard;
  }

  public float getAmountCreditCard() {
    return amountCreditCard;
  }

  public void setAmountCreditCard(float amountCreditCard) {
    this.amountCreditCard = amountCreditCard;
  }

  public float getAmountCash() {
    return amountCash;
  }

  public void setAmountCash(float amountCash) {
    this.amountCash = amountCash;
  }

  public String getCheckNumber() {
    return checkNumber;
  }

  public void setCheckNumber(String checkNumber) {
    this.checkNumber = checkNumber;
  }

  public String getCheckBank() {
    return checkBank;
  }

  public void setCheckBank(String checkBank) {
    this.checkBank = checkBank;
  }

  public Date getPaymentDate() {
    return paymentDate;
  }

  public void setPaymentDate(Date paymentDate) {
    this.paymentDate = paymentDate;
  }

  public float getCheckAmount() {
    return checkAmount;
  }

  public void setCheckAmount(float checkAmount) {
    this.checkAmount = checkAmount;
  }

  public void validate(Errors errors) {
    // TODO Auto-generated method stub
    
  }

  public String getTicketTypeSelected() {
    return ticketTypeSelected;
  }

  public void setTicketTypeSelected(String ticketTypeSelected) {
    this.ticketTypeSelected = ticketTypeSelected;
  }

  public Map<String, String> getTicketTypes() {
    return ticketTypes;
  }

}
